# 要做个简单的代理池，要完成以下三步内容：
# 一是完成代理地址的抓取，这里我们选择89免费代理来进行抓取，不用太多，几十个就够用了。
# 二是要对抓取的地址进行有效性检测，可以用百度大黑子的地址来进行测试。
# 三是对地址进行保存，由于不常使用，直接保存到文本文件即可。
# https://openatomworkshop.csdn.net/674695643a01316874d9198c.html
import random

# 第一步：导入模块
# 导入requests模块
import requests
# 从bs4中导入BeautifulSoup模块
from bs4 import BeautifulSoup
from win32ctypes.pywin32.pywintypes import datetime


# pip install lxml


# 站大爷(不能用爬虫，封号，改用js脚本)
# https://www.zdaye.com/free/
# let ips=''
# $('#ipc>tbody>tr').each(function() {
# var ip = $(this).find('td').eq(0).text(); // 获取第一个td的值
# var port = $(this).find('td').eq(1).text(); // 获取第二个td的值
# ips=ips+'\n'+'http://'+ip+':'+port
# });
# console.log(ips)

# 89免费代理
# https://www.89ip.cn/
# 代理IP检测
# https://www.89ip.cn/check.html



# 第二步：批量获取代理地址
# 这次使用89免费代理，地址为https://www.89ip.cn/index_1.html，经过手动抽样测试，地址有效。我们使用chrome浏览器打开地址，在检查功能中，通过元素选择来确定ip与port的元素标签
# 因为要获取表中的所有数据，我们先通过layui-table类名获取整张表格数据，再逐步提取tr->td标签，获取每行的数据，并保存到列表中，为了方便后期使用，我们固定保存的格式为：“http://ip:port”。
# 以下是获取代理地址的方法，这里pages参数是需要抓取页面的数量，ua是User-Agent参数，这两个参数值在第三步的主函数里，标签获取使用BeautifulSoup.find_all()方法，该方法最终返回一个代理地址列表。

# 定义获取代理地址的方法
def get_proxy(pages, ua):
    # 定义proxy_ips列表存储代理地址
    proxy_ips = []
    # 设置headers
    headers = {"User-Agent": ua}
    # 从第一页开始循环访问
    for page in range(1, pages + 1):
        print(f"正在爬取第{page}页!")
        url = "https://www.89ip.cn/index_{page}.html"
        res = requests.get(url, headers=headers)
        # 使用.text属性获取网页内容，赋值给html
        html = res.text
        # 用BeautifulSoup()传入变量html和解析器lxml，赋值给soup
        soup = BeautifulSoup(html, "lxml")
        # 使用find_all()方法查找类名为layui-table的标签
        table = soup.find_all(class_="layui-table")[0]
        # 使用find_all()方法查找tr标签
        trs = table.find_all("tr")
        # 使用for循环逐个访问trs列表中的tr标签,一个tr代表一行，第一行为表头，不记录
        for i in range(1, len(trs)):
            # 使用find_all()方法查找td标签
            ip = trs[i].find_all("td")[0].text.strip()
            port = trs[i].find_all("td")[1].text.strip()
            # 拼接代理地址
            proxy_ip = f"http://{ip}:{port}"
            # 将获取的代理地址保存到proxy_ips列表
            proxy_ips.append(proxy_ip)
    # 返回proxy_ips列表
    return proxy_ips


# 第三步：地址有效性检测
# 获得proxy_ips列表后，我们通过访问"https://www.baidu.com"地址进行有效性验证。
# 以下是获取代理地址的方法，其中ip上第一步获取到的地址，ua为User-Agent，这里设置了超时限制，如果3秒内未访问成功，则返回请求超时，该代理地址在后面会丢弃，该方法最终返回网页访问状态。
# 定义代理地址有效性验证方法
def test_proxy(ip, ua):
    # 设置headers
    headers = {"User-Agent": ua}
    url = "https://www.baidu.com"
    # 设置代理信息
    proxies = {"http": ip}
    # 通过请求百度首页来验证代理地址是否有效
    try:
        res = requests.get(url, headers=headers, proxies=proxies, timeout=3)
        print('请求成功', url, headers, proxies)
    except requests.exceptions.Timeout:
        # 超过3秒未返回，则请求超时
        print("请求超时")
        result_code = 0
    else:
        result_code = res.status_code
    # finally:
    #     return res.status_code
    # 返回请求状态
    return result_code


# 第四步：主函数与地址保存
# 由于保存比较简单我们与主函数写在一起即可
# 判断第二步的返回值是否为200，将返回值为200的代理地址保存到good_ips 列表当中。最后使用with open()将good_ips 列表中的数据写入“代理池_20241225.txt”文件
# 主函数
if __name__ == "__main__":
    # 定义good_ips列表用于存储有效的代理地址
    good_ips = []
    # 定义User-Agent参数
    ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36"
    # 设置获取页面的数量
    pages = 10
    # 调用get_proxy方法获取网站上的免费代理
    proxy_list = get_proxy(pages, ua)
    # 输出获取结果
    print(f"共爬取了 {len(proxy_list)} 个代理地址!")

    # 对获取的代理地址逐个进行有效性验证
    for ip in proxy_list:
        # 调用验证方法
        result = test_proxy(ip, ua)
        # 判断返回状态是否为200
        if result == 200:
            # 如果返回状态是为200，则保存到good_ips列表中
            good_ips.append(ip)
        else:
            # 否则continue
            continue
    # 输出检测结果
    print(f"共有 {len(good_ips)} 个代理地址通过了检测!")

    # 保存有效代理地址到文件中
    current_date = datetime.now().strftime("%Y%m%d")
    random_number = random.randint(1000, 9999)
    filename = f"代理池_{current_date}_{random_number}.txt"
    with open(filename, "a") as fp:
        # 将地址逐个写入txt文件中
        for i in good_ips:
            fp.write(f"{i}" + "\n")
    print(f"代理地址保存完毕", filename)
